package cn.jbolt.core.gen;

import cn.hutool.core.util.StrUtil;
import cn.hutool.setting.Setting;
import cn.hutool.setting.SettingUtil;
import cn.jbolt.core.base.JBoltIDGenMode;
import cn.jbolt.core.base.config.JBoltConfig;
import cn.jbolt.core.db.sql.DBType;
import cn.jbolt.core.util.JBoltArrayUtil;
import cn.jbolt.core.util.JBoltConsoleUtil;
import cn.jbolt.core.util.JBoltDesUtil;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.druid.DruidPlugin;

import javax.sql.DataSource;
import java.io.File;

/**
 * jfinal model Generator 主要用来生成Model和BaseModel
 *
 * @ClassName: JFinalModelGenerator
 * @author: JFinal学院-小木 QQ：909854136
 * @date: 2019年12月10日
 */
public class JFinalModelGenerator {
	public final String SEPARATOR = File.separator;
	private DruidPlugin druidPlugin;
	private String dbType;
	private boolean generateView;

	/**
	 * 根据configName得到数据源
	 *
	 * @param configName
	 * @return
	 */
	private DataSource getDataSource(String configName) {
		if (configName == null || configName.equals("main")) {
			return getMainDataSource();
		}
		return getExtendDataSource(configName);
	}

	/**
	 * 得到扩展数据源
	 *
	 * @param configName
	 * @return
	 */
	private DataSource getExtendDataSource(String configName) {
		JBoltConfig.loadConfig();
		String projectPath = System.getProperty("user.dir");
		Setting setting = SettingUtil.get(
				projectPath + SEPARATOR + "src" + SEPARATOR + "main" + SEPARATOR + "resources" + SEPARATOR + "dbconfig"
						+ SEPARATOR + "extend_datasource" + (JBoltConfig.pdevIsPro() ? "_pro" : "") + ".setting");
		String user = setting.get(configName, "user");
		String password = setting.get(configName, "password");
		boolean is_encrypted = setting.getBool("is_encrypted",configName,false);
		if(is_encrypted){
			user = JBoltDesUtil.getDecryptData(user);
			password = JBoltDesUtil.getDecryptData(password);
		}
		druidPlugin = new DruidPlugin(setting.get(configName, "jdbc_url"), user,password);
		druidPlugin.setConnectionProperties("remarks=true");
		dbType = setting.get(configName, "db_type");
		JBoltProjectGenConfig.setDbConfig(dbType, setting.get(configName, "jdbc_url"), user,password);
		boolean success = druidPlugin.start();
		return success ? druidPlugin.getDataSource() : null;
	}

	private DataSource getMainDataSource() {
		druidPlugin = JBoltConfig.createDruidPlugin();
		druidPlugin.setConnectionProperties("remarks=true");
		dbType = PropKit.get("db_type");

		String user = JBoltConfig.prop.get("user");
		String password = JBoltConfig.prop.get("password");
		boolean is_encrypted = JBoltConfig.prop.getBoolean("is_encrypted",false);
		if(is_encrypted){
			user = JBoltDesUtil.getDecryptData(user);
			password = JBoltDesUtil.getDecryptData(password);
		}

		JBoltProjectGenConfig.setDbConfig(dbType, PropKit.get("jdbc_url"), user,password);
		boolean success = druidPlugin.start();
		return success ? druidPlugin.getDataSource() : null;
	}

	/**
	 * 执行生成
	 * @param configName
	 * @param dataDictionaryVersion
	 * @param dataDictionaryDescription
	 * @return
	 */
	public boolean generate(String configName, String dataDictionaryVersion, String dataDictionaryDescription) {
		try {
			DataSource dataSource = getDataSource(configName);
			if (dataSource == null) {
				JBoltConsoleUtil.printMessage("=====JFinalModelGenerator.run dataSource Error====");
				return false;
			}
			// 创建生成器
			final JBoltGenerator generator = new JBoltGenerator(configName, dataSource, dataDictionaryVersion,
					dataDictionaryDescription);
			if (StrKit.notBlank(configName) && configName.equalsIgnoreCase("main") == false) {
				String mappingKitClassName = "_" + StrKit.firstCharToUpperCase(configName) + "MappingKit";
				generator.setMappingKitClassName(mappingKitClassName);
			}
			generator.setGenerateRemarks(true);
			generator.setGenerateView(JBoltProjectGenConfig.generateView);
			// 设置是否在 Model 中生成 dao 对象
			generator.setGenerateDaoInModel(JBoltProjectGenConfig.generateDaoInModel);
			// 设置是否生成字典文件
			generator.setGenerateDataDictionary(true);
			// 设置是否生成setter链
			generator.setGenerateChainSetter(JBoltProjectGenConfig.generateChainSetterInBaseModel);
			// 设置需要被移除的表名前缀用于生成modelName。例如表名 "osc_user"，移除前缀 "osc_"后生成的model名为 "User"而非
			// OscUser
			String remove = JBoltProjectGenConfig.removedTableNamePrefixes.trim();
			if (StrUtil.isNotBlank(remove)) {
				String[] arr = JBoltArrayUtil.from(remove, ",");
				if (arr != null && arr.length > 0) {
					generator.setRemovedTableNamePrefixes(arr);
				}
			}

			if (DBType.isPostgresql(dbType)) {
				// postgresql特殊处理
				generator.addTypeMapping("org.postgresql.geometric.PGpoint", "org.postgresql.geometric.PGpoint");
				generator.addTypeMapping("org.postgresql.geometric.PGbox", "org.postgresql.geometric.PGbox");
				generator.addTypeMapping("org.postgresql.geometric.PGlseg", "org.postgresql.geometric.PGlseg");
				generator.addTypeMapping("org.postgresql.geometric.PGpath", "org.postgresql.geometric.PGpath");
				generator.addTypeMapping("org.postgresql.geometric.PGpolygon", "org.postgresql.geometric.PGpolygon");
				generator.addTypeMapping("org.postgresql.geometric.PGcircle", "org.postgresql.geometric.PGcircle");
				generator.addTypeMapping("org.postgresql.geometric.PGline", "org.postgresql.geometric.PGline");
			}

			JBoltConsoleUtil.printMessageWithDate("Model Generator is Running...");
			generator.generate();
		} finally {
			if (druidPlugin != null) {
				druidPlugin.stop();
			}
			JBoltConsoleUtil.printMessageWithDate("Model Generator OK！");
		}
		return true;
	}

	public static void main(String[] args) {
		// 要生成的代码是在哪个项目下面 设置项目跟路径
		String projectRootPath = System.getProperty("user.dir");
		// 数据源配置名称 默认主数据源是main 其他的在extend_datasource.setting里配置的
		String configName = "main";
		// 指定本次运行直接生成的表名 忽略其它所有表 数组为空 表示忽略此强制设定 当需要单个指定生成时才需要这个
		String[] tableNames = new String[] {"jb_dictionary_type","jb_dictionary" /* "jb_user","jb_application" */ };
		//哪些前缀名的要生成
		String[] tableNamesPrefixes = new String[] {/* "jb_","pl_" */};
		//是否生成数据库视图view
		boolean generateView = false;
		// 生成Model放在哪个包下
		String modelPackage = "cn.jbolt.core.model";
		// 默认ID生成模式
		String idGenMode = JBoltIDGenMode.SNOWFLAKE;// auto|snowflake|sequence
		// 数据库字典文件版本号 自己定义
		String dataDictionaryVersion = "1.0.0";
		// 数据流字典文件的简介描述信息
		String dataDictionaryDescription = "JBolt极速开发平台"
				+ (configName.equals("main") ? "主数据源" : "扩展数据源[" + configName + "]") + "数据库字典";
		// 是否生成Model和BaseModel 如果设置为false 则只判断是否生成字典文件 直接不进行model和baseModel的生成
		boolean genModel = true;
		//是否强制覆盖model 默认不覆盖model 只覆盖baseModel
		boolean cover    = false;
		// 本次执行生成 是否生成JBolt核心库 model和baseModel 一般只生成自己的业务表 就设置为false
		// 注意自己的业务表不要使用jb_开头的前缀
		boolean genJBoltCoreModel = true;
		// 是否生成html格式数据字典
		boolean genHtmlDataDictionary = true;
		// 生成的Model java类需要去掉的前缀 多个用逗号隔开 内置已经去掉了核心表的前缀jb_
		String removedTableNamePrefixes = "jb_";

		// 下面这个默认是null就行 自定义的数据库字段转驼峰getter属性名的策略，
		// 默认使用策略已经够用，如果你有特殊需求就在这里定义它
		JBoltColumnToBuildAttrNameFunction columnTobuildAttrNameFun = null;
//		JBoltColumnToBuildAttrNameFunction columnTobuildAttrNameFun = new JBoltColumnToBuildAttrNameFunction() {
//			@Override
//			public String build(String column) {
//				//这里column就是数据库里的一个字段 然后你通过处理返回一个应有的定制格式即可
//				return null;
//			}
//		};

		// 初始化项目配置
		JBoltProjectGenConfig.init(projectRootPath, modelPackage, genModel, idGenMode, genHtmlDataDictionary,
				genJBoltCoreModel, removedTableNamePrefixes, columnTobuildAttrNameFun, tableNames,tableNamesPrefixes,generateView,null,cover);
		// 执行Model、BaseModel、数据字典Html的生成
		new JFinalModelGenerator().generate(configName, dataDictionaryVersion, dataDictionaryDescription);
	}
}
